package erfgame.core.world.terrain;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;


public class GridRectangle {
	private int eastX;
	private int eastY;
	private int westX;
	private int westY;
	private int northX;
	private int northY;
	private int southX;
	private int southY;
	
	private List<GridEdge>[] edges;
	private List<Point> area;
	
	public GridRectangle( int x1, int y1, int x2, int y2 ) {
		calculateCorners( x1, y1, x2, y2 );
	}
	
	private void calculateCorners( int gx1, int gy1, int gx2, int gy2 ) {
		// work out cardinal points
		int c1a = gy1 + 2 * gx1;
		if( (c1a & 1) == 0 ) {
			c1a++;
		}
		int c2a = gy2 - 2 * gx2;
		if( (c2a & 1) == 0 ) {
			c2a--;
		}
		int gxintersectionA = (c1a - c2a) / 4;
		int gyintersectionA = (c1a + c2a) / 2;

		int c1b = gy1 - 2 * gx1;
		if( (c1b & 1) == 0 ) {
			c1b--;
		}
		int c2b = gy2 + 2 * gx2;
		if( (c2b & 1) == 0 ) {
			c2b++;
		}
		int gxintersectionB = (c2b - c1b) / 4;
		int gyintersectionB = (c1b + c2b) / 2;

		int neDimension = ( gyintersectionA - gy1 );
		int seDimension = ( gyintersectionA - gy2 );
		
		if( neDimension < 0 && seDimension < 0 ) {
			northX = gxintersectionA;
			northY = gyintersectionA;
			southX = gxintersectionB;
			southY = gyintersectionB;
			westX = gx1;
			westY = gy1;
			eastX = gx2;
			eastY = gy2;
		} else if( neDimension < 0 ) {
			northX = gx2;
			northY = gy2;
			southX = gx1;
			southY = gy1;			
			westX = gxintersectionB;
			westY = gyintersectionB;
			eastX = gxintersectionA;
			eastY = gyintersectionA;
		} else if( seDimension < 0 ) {
			northX = gx1;
			northY = gy1;
			southX = gx2;
			southY = gy2;			
			westY = gyintersectionA;
			westX = gxintersectionA;
			eastY = gyintersectionB;
			eastX = gxintersectionB;
		} else {
			northX = gxintersectionB;
			northY = gyintersectionB;
			southX = gxintersectionA;
			southY = gyintersectionA;
			westX = gx2;
			westY = gy2;
			eastX = gx1;
			eastY = gy1;
		}
	}
	
	public int getNorthEastDimension() {
		return westY - northY;
	}
	
	public int getNorthWestDimension() {
		return eastY - northY;
	}

	public int getEastX() {
		return eastX;
	}

	public int getEastY() {
		return eastY;
	}

	public int getWestX() {
		return westX;
	}

	public int getWestY() {
		return westY;
	}

	public int getNorthX() {
		return northX;
	}

	public int getNorthY() {
		return northY;
	}

	public int getSouthX() {
		return southX;
	}

	public int getSouthY() {
		return southY;
	}
	

	public List<GridEdge> getGridEdges( int edgeIndex ) {
		if( edges == null ) {
			edges = calculateEdges();
		}
		return this.edges[ edgeIndex ];
	}
	
	public List<Point> getArea() {
		if( area == null ) {
			area = calculateArea();
		}
		return this.area;
	}
	
	private List<GridEdge>[] calculateEdges() {
		List<GridEdge>[] edges = new List[4];

		int neDimension = this.getNorthEastDimension() + 1;
		int seDimension = this.getNorthWestDimension() + 1;
		Point result = new Point();
		for( int dir=4; dir>0; ) {
			dir--;
			int dimension;
			int edgeIndex;
			int gx;
			int gy;
			switch( dir ) {
			case 3:
				// ne
				dimension = neDimension;
				edgeIndex = BlockGridTiles.INDEX_NE;
				gx = getWestX();
				gy = getWestY();
				break;
			case 2:
				// se
				dimension = seDimension;
				edgeIndex = BlockGridTiles.INDEX_SE;
				gx = getNorthX();
				gy = getNorthY();
				break;
			case 1:
				// sw
				dimension = neDimension;
				edgeIndex = BlockGridTiles.INDEX_SW;
				gx = getEastX();
				gy = getEastY();
				break;
			case 0:
			default:
				// nw
				dimension = seDimension;
				edgeIndex = BlockGridTiles.INDEX_NW;
				gx = getSouthX();
				gy = getSouthY();
				break;
			}
			List<GridEdge> directionEdges = new ArrayList<GridEdge>( dimension );
			for( int i=dimension; i>0; ) {
				i--;
				
				GridEdge edge = new GridEdge( gx, gy, edgeIndex );
				directionEdges.add( edge );
				if( i >= 0 ) {
					TerrainUtils.getGridCoordinates(gx, gy, edgeIndex, result);
					gx = result.x;
					gy = result.y;
				}
			}
			edges[dir] = directionEdges;
		}
		
		return edges;
	}
	
	private List<Point> calculateArea() {
		int neDimension = this.getNorthEastDimension() + 1;
		int nwDimension = this.getNorthWestDimension() + 1;
		ArrayList<Point> area = new ArrayList<Point>( 
				(neDimension) * (nwDimension)
		);
		Point nePoint = new Point(getNorthX(), getNorthY());
		for( int i=nwDimension; i>0; ) {
			i--;
			int sgx = nePoint.x;
			int sgy = nePoint.y;
			Point point = new Point( sgx, sgy );
			for( int j=neDimension; j>0; ) {
				j--;
				int gx = point.x;
				int gy = point.y;
				area.add( new Point( gx, gy ) );
				TerrainUtils.getGridCoordinates(gx, gy, BlockGridTiles.INDEX_SW, point);
			}
			TerrainUtils.getGridCoordinates(sgx, sgy, BlockGridTiles.INDEX_SE, nePoint);
		}
		return area;
	}
}
